package Model.Draw.Entities;

import Model.Core.IEntity;
import Model.Core.Impl.MessageEntity;
import Model.Draw.ICommunicatorDraw;
import Model.Draw.IEntityDraw;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.RenderingHints;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;

/**
 * TCC Project
 * @author jose.luz
 */
public class MessageDraw implements IEntityDraw {

    private MessageEntity messageEntity;
    private LinkDraw parentLink;
    private ICommunicatorDraw target;
    private boolean selected;
    private Rectangle2D messageRectangle;
    private Color color;

    public MessageDraw(LinkDraw parentLink, ICommunicatorDraw target) {
        this.parentLink = parentLink;
        this.target = target;
        selected = false;
        color = Color.green.darker();
    }

    public Color getColor() {
        if (selected) {
            return Color.RED;
        }
        return color;
    }

    @Override
    public void setEntity(IEntity entity) {
        messageEntity = (MessageEntity) entity;
    }

    @Override
    public IEntity getEntity() {
        return messageEntity;
    }

    @Override
    public void draw(Graphics g) {
        if (target instanceof ObjectDraw) {
            if (parentLink.getSourceDraw() instanceof ObjectDraw && ((ObjectDraw) parentLink.getSourceDraw()).equals(parentLink.getTargetDraw())) {
                Graphics2D g2 = (Graphics2D) g;
                Point p1 = new Point((int) parentLink.getLineDrawAutoMessage().getP1().getX(), (int) parentLink.getLineDrawAutoMessage().getP1().getY() - 20);
                Point p2 = new Point((int) parentLink.getLineDrawAutoMessage().getP2().getX(), (int) parentLink.getLineDrawAutoMessage().getP2().getY() - 20);
                drawArrow(g, p1, p2);
                drawString(g, p1, p2);
            } else {
                Line2D parentLine = parentLink.getLineDraw();

                double x1 = parentLine.getX1();
                double x2 = parentLine.getX2();
                double y1 = parentLine.getY1();
                double y2 = parentLine.getY2();
                if (parentLink.getSourceDraw().equals(target)) {
                    x1 = parentLine.getX2();
                    x2 = parentLine.getX1();
                    y1 = parentLine.getY2();
                    y2 = parentLine.getY1();
                }

                double L = Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));

                int offsetPixels = 15; // This is the second line
                double x1p = (x1 + offsetPixels * (y2 - y1) / L);
                double x2p = (x2 + offsetPixels * (y2 - y1) / L);
                double y1p = (y1 + offsetPixels * (x1 - x2) / L);
                double y2p = (y2 + offsetPixels * (x1 - x2) / L);
                double coefAngular = (y2p - y1p) / (x2p - x1p);
                double coefLinear = y2p - coefAngular * x2p;

                double distReta = calculateDistance((int) x1p, (int) y1p, (int) x2p, (int) y2p);
                int loop = 0;
                while ((distReta < 80 || distReta > 120) && loop < 1000) {
                    if (distReta < 40) {
                        if (x1p < x2p) {
                            x1p = x1p - 5;
                            y1p = coefAngular * (x1p) + coefLinear;
                            x2p = x2p + 5;
                            y2p = coefAngular * (x2p) + coefLinear;
                        } else {
                            x1p = x1p + 5;
                            y1p = coefAngular * (x1p) + coefLinear;
                            x2p = x2p - 5;
                            y2p = coefAngular * (x2p) + coefLinear;
                        }

                    } else {
                        if (x1p < x2p) {
                            x1p = x1p + 5;
                            y1p = coefAngular * (x1p) + coefLinear;
                            x2p = x2p - 5;
                            y2p = coefAngular * (x2p) + coefLinear;
                        } else {
                            x1p = x1p - 5;
                            y1p = coefAngular * (x1p) + coefLinear;
                            x2p = x2p + 5;
                            y2p = coefAngular * (x2p) + coefLinear;
                        }
                    }
                    loop++;
                    distReta = calculateDistance((int) x1p, (int) y1p, (int) x2p, (int) y2p);
                }

                if (parentLink.getTargetDraw().equals(target)) {
                    if (((ObjectDraw) target).getTop().getJoint().getX().getCoordinate() < parentLink.getTargetDraw().getTop().getJoint().getX().getCoordinate()) {
                        drawArrow(g, new Point((int) x2p, (int) y2p), new Point((int) x1p, (int) y1p));
                        drawString(g, new Point((int) x2p, (int) y2p), new Point((int) x1p, (int) y1p));
                    } else {
                        drawArrow(g, new Point((int) x1p, (int) y1p), new Point((int) x2p, (int) y2p));
                        drawString(g, new Point((int) x1p, (int) y1p), new Point((int) x2p, (int) y2p));
                    }
                } else {
                    if (((ObjectDraw) target).getTop().getJoint().getX().getCoordinate() < ((ObjectDraw) parentLink.getSourceDraw()).getTop().getJoint().getX().getCoordinate()) {
                        drawArrow(g, new Point((int) x2p, (int) y2p), new Point((int) x1p, (int) y1p));
                        drawString(g, new Point((int) x2p, (int) y2p), new Point((int) x1p, (int) y1p));
                    } else {
                        drawArrow(g, new Point((int) x1p, (int) y1p), new Point((int) x2p, (int) y2p));
                        drawString(g, new Point((int) x1p, (int) y1p), new Point((int) x2p, (int) y2p));
                    }
                }
            }
        }
    }

    private double calculateDistance(int xa, int ya, int xb, int yb) {
        return Math.sqrt(Math.pow((xa - xb), 2) + Math.pow((ya - yb), 2));
    }

    private void drawArrow(Graphics g, Point p1, Point p2) {
        double dia = 25.0;
        double barb = 15.0;
        double phi = Math.toRadians(20);
        Graphics2D g2 = (Graphics2D) g;
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);
        double dy = p2.y - p1.y;
        double dx = p2.x - p1.x;
        double theta = Math.atan2(dy, dx);
        double x1 = p1.x + (dia / 2) * Math.cos(theta);
        double y1 = p1.y + (dia / 2) * Math.sin(theta);
        theta += Math.PI;
        double x2 = p2.x + (dia / 2) * Math.cos(theta);
        double y2 = p2.y + (dia / 2) * Math.sin(theta);
        g2.setPaint(Color.green.darker());
        g2.draw(new Line2D.Double(x1, y1, x2, y2));
        double xa = x2 + barb * Math.cos(theta + phi);
        double ya = y2 + barb * Math.sin(theta + phi);
        //g2.draw(new Line2D.Double(x2, y2, x, y));
        double xb = x2 + barb * Math.cos(theta - phi);
        double yb = y2 + barb * Math.sin(theta - phi);
        //g2.draw(new Line2D.Double(x2, y2, x, y));
        int[] xPoints = {(int) x2, (int) xa, (int) xb};
        int[] yPoints = {(int) y2, (int) ya, (int) yb};
        Polygon p = new Polygon(xPoints, yPoints, 3);
        g2.draw(p);
        g2.fill(p);
    }

    private void drawString(Graphics g, Point p, Point p2) {
        int x, y;
        if (parentLink.getSourceDraw() instanceof ObjectDraw && ((ObjectDraw) parentLink.getSourceDraw()).equals(parentLink.getTargetDraw())) {
            x = (int)p.getX();
            y = (int)p.getY() - 20;
        } else {
            if (p.x < p2.x) {
                if (p.y < p2.y) {
                    x = p.x + 20;
                    y = p.y + 20;
                } else {
                    x = p.x + 20;
                    y = p2.y - 20;
                }
            } else {
                if (p.y > p2.y) {
                    x = p2.x + 25;
                    y = p.y + 20;
                } else {
                    x = p2.x + 20;
                    y = p2.y - 20;
                }
            }
        }
        if (messageEntity == null || messageEntity.getDescription() == null || messageEntity.getDescription().isEmpty()) {
            messageEntity.setDescription("1. ret:metodo(a)");
        }
        Font mFont = g.getFont();
        messageRectangle = mFont.getStringBounds(messageEntity.getDescription(), ((Graphics2D) g).getFontRenderContext());
        messageRectangle.setRect((int) x, (int) y - messageRectangle.getHeight() * 0.8, (int) messageRectangle.getWidth(), (int) messageRectangle.getHeight());
        g.setColor(getColor());
        g.drawString(messageEntity.getDescription(), x, y);
    }

    @Override
    public boolean contains(int x, int y) {
        if (messageRectangle != null) {
            return messageRectangle.contains(x, y);
        }
        return false;
    }

    @Override
    public void select() {
        selected = true;
    }

    @Override
    public void unselect() {
        selected = false;
    }

    @Override
    public void move(int diffX, int diffY) {
    }

    @Override
    public void rename(String newName) {
        messageEntity.setDescription(newName);
    }
}
